#pragma once
#include "message.hpp"
#include "net.hpp"
#include "abstract.hpp"

namespace ns_dispacher
{
    class Callback
    {
    public:
        using ptr = std::shared_ptr<Callback>;
        virtual void onMessage(const BaseConnection::ptr& conn, BaseMessage::ptr& msg) = 0;

    };

    template <class T>
    class CallbackT : public Callback
    {
    public:
        using ptr = std::shared_ptr<CallbackT<T>>;
        using messagecb = std::function<void(const BaseConnection::ptr& conn, std::shared_ptr<T>& msg)>;
        CallbackT(const messagecb& cb)
        :_cb(cb)
        {}
        virtual void onMessage(const BaseConnection::ptr& conn, BaseMessage::ptr& msg) override
        {
            auto type_msg = std::dynamic_pointer_cast<T>(msg);
            _cb(conn,type_msg);
        }
    private:
        messagecb _cb;
    };
    class Dispacher
    {
    public:
        using ptr = std::shared_ptr<Dispacher>;
        template <class T>
        void Registercb(Mtype mtype,const typename CallbackT<T>::messagecb& cb)
        {
            std::unique_lock<std::mutex> mutex(_mutex);

            auto cbptr = std::make_shared<CallbackT<T>>(cb);
            _hashcb.insert(std::make_pair(mtype,cbptr));
        }

    //using MessageCallback = std::function<void(const BaseConnection::ptr&, BaseMessage::ptr&)>;
        void OnMessage(const ns_rpc::BaseConnection::ptr& conn,ns_rpc::BaseMessage::ptr& msg)
        {
            // 这是根据_hashcb的消息类型，匹配的onMessagecb，会设置到server/client的setMessagecb中
            std::unique_lock<std::mutex> mutex(_mutex);
            auto it = _hashcb.find(msg->GetMtype());
            if (it != _hashcb.end())
            {
                return it->second->onMessage(conn,msg);
            }
            //未返回，不可能
            LOG(ERROR,"未知错误");
            conn->shutdown();
        }
        private:
            std::mutex _mutex;
            std::unordered_map<Mtype, Callback::ptr> _hashcb;
    };
}